]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Searcher.c
mDNSResponder-58.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Searcher.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.13 2003/08/14 02:19:54 cheshire
27 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
28
29 Revision 1.12 2003/08/12 19:56:24 cheshire
30 Update to APSL 2.0
31
32 */
33
34 #include <stdio.h> // For printf()
35 #include <Events.h> // For WaitNextEvent()
36 #include <SIOUX.h> // For SIOUXHandleOneEvent()
37
38 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
39 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
40
41 typedef struct
42 {
43 OTLIFO serviceinfolist;
44 Boolean headerPrinted;
45 Boolean lostRecords;
46 } SearcherServices;
47
48 typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo;
49
50 // These don't have to be globals, but their memory does need to remain valid for as
51 // long as the search is going on. They are declared as globals here for simplicity.
52 #define RR_CACHE_SIZE 1000
53 static CacheRecord rrcachestorage[RR_CACHE_SIZE];
54 static mDNS mDNSStorage;
55 static mDNS_PlatformSupport PlatformSupportStorage;
56 static SearcherServices services;
57 static DNSQuestion browsequestion, domainquestion;
58
59 // PrintServiceInfo prints the service information to standard out
60 // A real application might want to do something else with the information
61 static void PrintServiceInfo(SearcherServices *services)
62 {
63 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
64
65 while (link)
66 {
67 linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link);
68 ServiceInfo *s = &ls->i;
69
70 if (!services->headerPrinted)
71 {
72 printf("%-55s Type Domain IP Address Port Info\n", "Name");
73 services->headerPrinted = true;
74 }
75
76 if (ls->dom)
77 {
78 char c_dom[256];
79 ConvertDomainNameToCString(&s->name, c_dom);
80 if (ls->add) printf("%-55s available for browsing\n", c_dom);
81 else printf("%-55s no longer available for browsing\n", c_dom);
82 }
83 else
84 {
85 domainlabel name;
86 domainname type, domain;
87 UInt16 port = (UInt16)((UInt16)s->port.b[0] << 8 | s->port.b[1]);
88 char c_name[64], c_type[256], c_dom[256], c_ip[20];
89
90 DeconstructServiceName(&s->name, &name, &type, &domain);
91 ConvertDomainLabelToCString_unescaped(&name, c_name);
92 ConvertDomainNameToCString(&type, c_type);
93 ConvertDomainNameToCString(&domain, c_dom);
94 sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
95
96 printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
97 if (ls->add) printf("%-15s %5d %#s\n", c_ip, port, s->TXTinfo);
98 else printf("Removed\n");
99 }
100
101 link = link->fNext;
102 OTFreeMem(ls);
103 }
104 }
105
106 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
107 // enqueues a record for PrintServiceInfo() to print.
108 // Note, a browsing application would *not* normally need to get all this information --
109 // all it needs is the name, to display to the user.
110 // Finding out the address, port, and txtinfo should be deferred to the time that the user
111 // actually needs to contact the service to use it.
112 static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
113 {
114 SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext;
115 linkedServiceInfo *info = (linkedServiceInfo *)(query->info);
116 if (query->info->ip.type == mDNSAddrType_IPv4)
117 {
118 mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient
119 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
120 OTFreeMem(query);
121 }
122 }
123
124 // When a new named instance of a service is found, FoundInstance() is called.
125 // In this sample code we turn around and immediately issue a query to resolve that service name to
126 // find its address, port, and txtinfo, but a normal browing application would just display the name.
127 static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
128 {
129 #pragma unused (question)
130 SearcherServices *services = (SearcherServices *)question->QuestionContext;
131 linkedServiceInfo *info;
132
133 debugf("FoundInstance %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
134
135 if (answer->rrtype != kDNSType_PTR) return;
136 if (!services) { debugf("FoundInstance: services is NULL"); return; }
137
138 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
139 if (!info) { services->lostRecords = true; return; }
140
141 info->i.name = answer->rdata->u.name;
142 info->i.InterfaceID = answer->InterfaceID;
143 info->i.ip.type = mDNSAddrType_IPv4;
144 info->i.ip.ip.v4 = zeroIPAddr;
145 info->i.port = zeroIPPort;
146 info->add = AddRecord;
147 info->dom = mDNSfalse;
148
149 if (!AddRecord) // If TTL == 0 we're deleting a service,
150 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
151 else // else we're adding a new service
152 {
153 ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery));
154 if (!q) { OTFreeMem(info); services->lostRecords = true; return; }
155 mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services);
156 }
157 }
158
159 static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
160 {
161 #pragma unused (m)
162 #pragma unused (question)
163 SearcherServices *services = (SearcherServices *)question->QuestionContext;
164 linkedServiceInfo *info;
165
166 debugf("FoundDomain %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
167
168 if (answer->rrtype != kDNSType_PTR) return;
169 if (!services) { debugf("FoundDomain: services is NULL"); return; }
170
171 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
172 if (!info) { services->lostRecords = true; return; }
173
174 info->i.name = answer->rdata->u.name;
175 info->i.InterfaceID = answer->InterfaceID;
176 info->i.ip.type = mDNSAddrType_IPv4;
177 info->i.ip.ip.v4 = zeroIPAddr;
178 info->i.port = zeroIPPort;
179 info->add = AddRecord;
180 info->dom = mDNStrue;
181
182 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
183 }
184
185 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
186 static Boolean YieldSomeTime(UInt32 milliseconds)
187 {
188 extern Boolean SIOUXQuitting;
189 EventRecord e;
190 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
191 SIOUXHandleOneEvent(&e);
192 return(SIOUXQuitting);
193 }
194
195 int main()
196 {
197 extern void mDNSPlatformIdle(mDNS *const m); // Only needed for debugging version
198 mStatus err;
199 Boolean DoneSetup = false;
200
201 SIOUXSettings.asktosaveonclose = false;
202 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
203 SIOUXSettings.rows = 40;
204 SIOUXSettings.columns = 132;
205
206 printf("Prototype Multicast DNS Searcher\n\n");
207 printf("WARNING! This is experimental software.\n\n");
208 printf("Multicast DNS is currently an experimental protocol.\n\n");
209 printf("This software reports errors using MacsBug breaks,\n");
210 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
211 printf("******************************************************************************\n");
212
213 err = InitOpenTransport();
214 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
215
216 err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
217 mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
218 if (err) return(err);
219
220 services.serviceinfolist.fHead = NULL;
221 services.headerPrinted = false;
222 services.lostRecords = false;
223
224 while (!YieldSomeTime(35))
225 {
226 // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
227 // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
228 mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
229 if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
230 {
231 domainname srvtype, srvdom;
232 DoneSetup = true;
233 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
234 MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
235 MakeDomainNameFromDNSNameString(&srvdom, "local.");
236 err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, FoundInstance, &services);
237 if (err) break;
238 err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, mDNSInterface_Any, FoundDomain, &services);
239 if (err) break;
240 }
241
242 if (services.serviceinfolist.fHead)
243 PrintServiceInfo(&services);
244
245 if (services.lostRecords)
246 {
247 services.lostRecords = false;
248 printf("**** Warning: Out of memory: Records have been missed.\n");
249 }
250 }
251
252 mDNS_StopBrowse(&mDNSStorage, &browsequestion);
253 mDNS_Close(&mDNSStorage);
254 return(0);
255 }